package top.wangjiu.java.jvm.attribute;

import top.wangjiu.java.jvm.AttributeInfo;
import top.wangjiu.java.jvm.attribute.info.ExeceptionInfo;
import top.wangjiu.java.jvm.constantinfo.ConstantPoolInfo;

import java.util.Arrays;

/**
 * Java程序方法体中的代码经过Javac编译器处理后，最终变为字节码指令存储在Code属性中。当然不是所有的方法都必须有这个属性（接口中的方法或抽象方法就不存在Code属性）
 *
 * max_stack：操作数栈深度最大值，在方法执行的任何时刻，操作数栈深度都不会超过这个值。虚拟机运行时根据这个值来分配栈帧的操作数栈深度
 *
 * max_locals：局部变量表所需存储空间，单位为Slot（参见备注四）。并不是所有局部变量占用的Slot之和，当一个局部变量的生命周期结束后，其所占用的Slot将分配给其它依然存活的局部变量使用，按此方式计算出方法运行时局部变量表所需的存储空间
 *
 * code_length和code：用来存放Java源程序编译后生成的字节码指令。code_length代表字节码长度，code是用于存储字节码指令的一系列字节流。
 *
 * 每一个指令是一个u1类型的单字节，当虚拟机读到code中的一个字节码（一个字节能表示256种指令，Java虚拟机规范定义了其中约200个编码对应的指令），就可以判断出该字节码代表的指令，指令后面是否带有参数，参数该如何解释，
 * 虽然code_length占4个字节，但是Java虚拟机规范中限制一个方法不能超过65535条字节码指令，如果超过，Javac将拒绝编译
 */
public class CodeAttr extends AttributeInfo {

    public final static String NAME = "Code";

    private final short attributeNameIndex;   //常量池中的uft8类型的索引，值固定为”Code“
    private final int attributeLength;       //属性长度 为整个属性表长度-6
    private final short maxStack;   //操作数栈的最大深度值，jvm运行时根据该值分配栈帧
    private final short maxLocals;  //局部变量表最大存储空间，单位是slot
    private final int  codeLength; // 字节码指令的个数
    private final byte[] codes; // 具体的字节码指令
    private final short exceptionTableLength; //异常的个数
    private final ExeceptionInfo[] execeptionTable;//具体的异常内容
    private final short attributesCount;     //属性的个数
    private final AttributeInfo[] attributes; //具体的属性内容

    public CodeAttr(short attributeNameIndex,int attributeLength, short maxStack,short maxLocals,byte[] codes,ExeceptionInfo[] execeptionTable,AttributeInfo[] attributes){
        this.attributeNameIndex = attributeNameIndex;
        this.attributeLength = attributeLength;
        this.maxStack = maxStack;
        this.maxLocals = maxLocals;
        this.codeLength = codes.length;
        this.codes = codes;
        this.exceptionTableLength = (short) execeptionTable.length;
        this.execeptionTable = execeptionTable;
        this.attributesCount = (short) attributes.length;
        this.attributes = attributes;
    }


    @Override
    public short attributeNameIndex() {
        return attributeNameIndex;
    }

    @Override
    public int attributeLength() {
        return attributeLength;
    }

    @Override
    public String toString(ConstantPoolInfo[] poolInfos) {
        StringBuilder sb = new StringBuilder("Code: stack="+maxStack+", locals="+maxLocals);
        sb.append("\n\t\t\t\tinstruct code:"+ Arrays.toString(codes));
        //字节码指令太多了，这里先不管了
//        sb.append("\n\t\t\t\tinstruct count:"+codeLength);
//        for (int i = 0; i < codeLength; i++) {
//            sb.append("\n\t\t\t\t\t"+i+": "+codes[i]);
//        }
        sb.append("\n\t\t\t\texception count:"+exceptionTableLength);
        for (int i = 0; i < exceptionTableLength; i++) {
            sb.append("\n\t\t\t\t\t"+execeptionTable[i].toString(poolInfos));
        }
        sb.append("\n\t\t\t\tAttribute count:"+attributesCount);
        for (int i = 0; i < attributesCount; i++) {
            sb.append("\n\t\t\t\t\t"+attributes[i].toString(poolInfos));
        }

        return sb.toString();
    }

}
